#include "com_br4mmie_asciistory_WorldRenderer.h"
#include "Includes.h"
#include "Shaders.h"
#include "ShaderLoader.h"
#include "Model.h"
#include "esUtil.h"
#include "Camera.h"
#include "MapObject.h"

int screenWidth;
int screenHeight;

ShaderInfo defaultShader;
Model* testModel = NULL;
Camera* camera = NULL;
std::vector<MapObject*> objects;
bool initialized = false;

char*  currentMap = NULL;
char*  bufferMap = NULL;
float* mapVertices = NULL;
int    nMapQuads;

void setVtx(float* vtx, float x, float y, float z)
{
	vtx[0] = x;
	vtx[1] = y;
	vtx[2] = z;
}
void generateMapVerts()
{
	if (mapVertices != NULL) delete[] mapVertices;

	nMapQuads = 0; int i=0;
	while (currentMap[i] != '\0')
	{
		if (currentMap[i++] != '\n') ++nMapQuads;
	}

	mapVertices = new float[nMapQuads * 18];
	int x = 0;
	int y = 0;
	i = 0;
	for (int a=0; currentMap[a] != '\0'; ++a)
	{
		if (currentMap[a] == '\n') 
		{
			++y;
			x=0;
		}
		else
		{
			setVtx(&mapVertices[i*18     ], x  , currentMap[a]/255.0f, y  );
			setVtx(&mapVertices[i*18 +  3], x+1, currentMap[a]/255.0f, y  );
			setVtx(&mapVertices[i*18 +  6], x  , currentMap[a]/255.0f, y+1);

			setVtx(&mapVertices[i*18 +  9], x  , currentMap[a]/255.0f, y+1);
			setVtx(&mapVertices[i*18 + 12], x+1, currentMap[a]/255.0f, y  );
			setVtx(&mapVertices[i*18 + 15], x+1, currentMap[a]/255.0f, y+1);

			++x;
			++i;
			if (i >= nMapQuads) break;
		}
	}
}
void onInit()
{
	ShaderLoader loader;
	GLuint vtx, frag;

	vtx =  loader.loadShader(GL_VERTEX_SHADER,   defaultVtx);
	frag = loader.loadShader(GL_FRAGMENT_SHADER, defaultFrag);

	defaultShader.program		= loader.createProgram(vtx, frag);
	defaultShader.position		= glGetAttribLocation(defaultShader.program,  "aPosition");
    defaultShader.normal		= glGetAttribLocation(defaultShader.program,  "aNormal");
    defaultShader.color			= glGetAttribLocation(defaultShader.program,  "aColor");
    defaultShader.texcoord		= glGetAttribLocation(defaultShader.program,  "aTexCoord");
    defaultShader.world			= glGetUniformLocation(defaultShader.program, "uWorld");
    defaultShader.view			= glGetUniformLocation(defaultShader.program, "uView");
    defaultShader.proj			= glGetUniformLocation(defaultShader.program, "uProjection");
    defaultShader.texture		= glGetUniformLocation(defaultShader.program, "texture");
    defaultShader.constants[0]	= glGetUniformLocation(defaultShader.program, "uLightDir");

	camera		= new Camera(Vector3(5, 15, 5), Vector3(0, -0.3, 1));
	testModel	= new Model("/sdcard/ASCIIStory/Data/Other/character.obj");
	bufferMap	= new char[110];
	strcpy(bufferMap, "xxxxxxxxxx\nx        x\nx        x\nx        x\nx        x\nx        x\nx        x\nx        x\nx        x\nxxxxxxxxxx\n");
	
	std::ofstream logfile("/sdcard/ASCIIStory/log.txt");
	logfile << "shader " << vtx << "/" << frag << "/" << defaultShader.program << std::endl;
	logfile << "model " << testModel->nVertices << std::endl;
	logfile.close();
	initialized = true;
}
void onCleanup()
{
	SAFE_DELETE(camera);
	SAFE_DELETE(testModel);

	if (currentMap == bufferMap) currentMap = NULL;
	else	SAFE_DELETE_ARRAY(currentMap);
			SAFE_DELETE_ARRAY(bufferMap);

	SAFE_DELETE_ARRAY(mapVertices);
}
JNIEXPORT void JNICALL Java_com_br4mmie_asciistory_WorldRenderer_onDrawFrame(JNIEnv *, jobject, jobject)
{
	if (!initialized) onInit();

	if (currentMap != bufferMap) 
	{
		if (currentMap != NULL) delete[] currentMap;
		currentMap = bufferMap;
		generateMapVerts();
	}

	glClearColor(0.0f, 0.3f, 0.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glActiveTexture(GL_TEXTURE0);
	glUseProgram(defaultShader.program);

	ESMatrix world, view, proj;
	esMatrixLoadIdentity(&world);
	esMatrixLoadIdentity(&view);
	esMatrixLoadIdentity(&proj);

	glUniform3f(defaultShader.constants[0], 1, 1, 1);
    world.Load (defaultShader.world);

	camera->setViewProj(defaultShader);

	glVertexAttribPointer(defaultShader.position, 3, GL_FLOAT, GL_FALSE, sizeof(float)*3, mapVertices);
	glEnableVertexAttribArray(defaultShader.position);
	glDrawArrays(GL_TRIANGLES, 0, nMapQuads*6);
	glDisableVertexAttribArray(defaultShader.position);
}
JNIEXPORT void JNICALL Java_com_br4mmie_asciistory_WorldRenderer_onSurfaceChanged(JNIEnv *, jobject, jobject, jint width, jint height)
{
	screenWidth = width;
	screenHeight = height;

	if (initialized) onCleanup();
	initialized = false;
}
JNIEXPORT void JNICALL Java_com_br4mmie_asciistory_WorldRenderer_onSurfaceCreated(JNIEnv *, jobject, jobject, jobject)
{
	if (initialized) onCleanup();
	initialized = false;
}
JNIEXPORT void JNICALL Java_com_br4mmie_asciistory_WorldRenderer_setMap(JNIEnv *env, jobject, jstring jmap)
{
	jboolean isCopy;
	const char* map = env->GetStringUTFChars(jmap, &isCopy);

	bufferMap = new char[strlen(map)+1];
	memcpy(bufferMap, map, strlen(map)+1);

	env->ReleaseStringUTFChars(jmap, map);
}
JNIEXPORT void JNICALL Java_com_br4mmie_asciistory_WorldRenderer_setCameraLock(JNIEnv *, jobject, jint x, jint y)
{
	if (initialized) 
	{
		camera->moveTo(Vector3(x, 5, y + 5));
		camera->lookDir(Vector3(0, 1, 1));
	}
}
JNIEXPORT void JNICALL Java_com_br4mmie_asciistory_WorldRenderer_addMapObject(JNIEnv *, jobject, jstring jimage, jint x, jint y)
{
	jboolean isCopy;
	const char* image = env->GetStringUTFChars(jimage, &isCopy);

	objects.push_back(new MapObject(image, x, y));

	env->ReleaseStringUTFChars(jimage, image);
}
